package com.xiyu.service.service.restaurant;

import com.xiyu.service.model.restaurant.recipe.RestaurantRecipe;
import com.xiyu.service.vo.restaurant.recipe.RecipePageQueryDetailOutput;
import com.xiyu.service.vo.restaurant.recipe.RecipePageQueryDetailInput;
import com.xiyu.service.model.restaurant.recipe.RestaurantCombo;
import com.xiyu.service.vo.restaurant.recipe.RecipeListQueryComboOutput;
import com.xiyu.service.util.entity.EntityUtils;
import com.xiyu.service.model.restaurant.recipe.*;
import com.xiyu.service.repository.restaurant.recipe.RestaurantComboRepository;
import com.xiyu.service.repository.restaurant.recipe.RestaurantRecipeDetailRepository;
import com.xiyu.service.repository.restaurant.recipe.RestaurantRecipeRepository;
import com.xiyu.service.vo.restaurant.recipe.RecipeComboGetOutput;
import com.xiyu.service.vo.restaurant.recipe.RecipeComboUpdateInput;
import com.xiyu.service.vo.restaurant.recipe.RecipeComboCreateInput;
import com.xiyu.service.vo.restaurant.recipe.RecipeComboQueryInput;
import com.xiyu.service.vo.restaurant.recipe.RecipeComboQueryOutput;
import com.xiyu.service.vo.restaurant.recipe.RecipeGetOutput;
import com.xiyu.service.vo.restaurant.recipe.RecipeUpdateInput;
import com.xiyu.service.vo.restaurant.recipe.RecipeCreateInput;
import com.xiyu.service.vo.restaurant.recipe.RecipeQueryOutput;
import com.xiyu.service.vo.restaurant.recipe.RecipeQueryInput;
import org.babyfish.jimmer.DraftObjects;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.babyfish.jimmer.Page;
import java.util.*;

import org.springframework.transaction.annotation.Transactional;
import com.xiyu.service.framework.web.web.core.pojo.PageResult;
import com.xiyu.service.convert.restaurant.RecipeConvert;

import static com.xiyu.service.framework.exception.util.ServiceExceptionUtil.exception;
import static com.xiyu.service.errorCode.restaurant.RecipeErrorCode.*;

/**
 * 食谱管理 Service 实现类
 */
@Service
@Validated
public class RecipeServiceImpl implements RecipeService {

    @Resource
    private RestaurantRecipeRepository restaurantRecipeRepository;

    @Resource
    private RestaurantRecipeDetailRepository restaurantRecipeDetailRepository;

    @Resource
    private RestaurantComboRepository restaurantComboRepository;

    @Override
    public PageResult<RecipeQueryOutput> query(RecipeQueryInput inputVO) {
        Page<RestaurantRecipe> recipePage = restaurantRecipeRepository.pageQuery(inputVO);
        List<RecipeQueryOutput> recipeList = RecipeConvert.INSTANCE.queryPageOutputConvert(recipePage.getRows());
        return new PageResult<>(recipeList, recipePage.getTotalRowCount());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(RecipeCreateInput inputVO) {
        Optional<RestaurantRecipe> opDupRecipe = restaurantRecipeRepository.findFirstByRecipeName(inputVO.getRecipeName());
        if(opDupRecipe.isPresent()){
            throw exception(RECIPE_EXISTS);
        }
        RestaurantRecipe newRecipe = RecipeConvert.INSTANCE.createInputConvert(inputVO);
        newRecipe = restaurantRecipeRepository.insert(newRecipe);
        return newRecipe.id();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(RecipeUpdateInput inputVO) {
        Optional<RestaurantRecipe> opDupRecipe = restaurantRecipeRepository.findFirstByRecipeNameAndIdNot(inputVO.getRecipeName(), inputVO.getId());
        if(opDupRecipe.isPresent()){
            throw exception(RECIPE_EXISTS);
        }
        for(RecipeUpdateInput.detail detail : inputVO.getDetails()){
            if(Objects.equals(detail.getOperateType(), "delete")){
                restaurantRecipeDetailRepository.deleteById(inputVO.getId());
            }else if(Objects.equals(detail.getOperateType(),"new")){
                RestaurantRecipeDetail newDetail = RecipeConvert.INSTANCE.updateInputConvert(detail);
                restaurantRecipeDetailRepository.insert(newDetail);
            }else{
                RestaurantRecipeDetail updateDetail = RecipeConvert.INSTANCE.updateInputConvert(detail);
                Optional<RestaurantRecipeDetail> opOldDetail = restaurantRecipeDetailRepository.findById(detail.getId());
                if(!opOldDetail.isPresent()){
                    throw exception(RECIPE_DETAIL_NOT_EXISTS);
                }
                if (!EntityUtils.isEquals(opOldDetail.get(), updateDetail)){
                    restaurantRecipeDetailRepository.update(updateDetail);
                }
            }
        }
        RestaurantRecipe updateRecipe = RecipeConvert.INSTANCE.updateInputConvert(inputVO);
        updateRecipe = RestaurantRecipeDraft.$.produce(updateRecipe, draft -> {
            DraftObjects.unload(draft, RestaurantRecipeProps.DETAILS);
        });
        restaurantRecipeRepository.update(updateRecipe);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleted(Long id) {
        Optional<RestaurantRecipe> opDupRecipe = restaurantRecipeRepository.findById(id);
        if(!opDupRecipe.isPresent()){
            throw exception(RECIPE_NOT_EXISTS);
        }
        restaurantRecipeRepository.deleteById(id);
        return true;
    }

    @Override
    public RecipeGetOutput get(Long id) {
        Optional<RestaurantRecipe> opDupRecipe = restaurantRecipeRepository.findDetailById(id);
        if(!opDupRecipe.isPresent()){
            throw exception(RECIPE_NOT_EXISTS);
        }
        return RecipeConvert.INSTANCE.getOutputConvert(opDupRecipe.get());
    }

    @Override
    public PageResult<RecipeComboQueryOutput> comboQuery(RecipeComboQueryInput inputVO) {
        Page<RestaurantCombo> recipePage = restaurantComboRepository.pageQuery(inputVO);
        List<RecipeComboQueryOutput> recipeList = RecipeConvert.INSTANCE.comboQueryOutputConvert(recipePage.getRows());
        return new PageResult<>(recipeList, recipePage.getTotalRowCount());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long comboCreate(RecipeComboCreateInput inputVO) {
        Optional<RestaurantCombo> opDupCombo = restaurantComboRepository.findFirstByComboName(inputVO.getComboName());
        if(opDupCombo.isPresent()){
            throw exception(COMBO_EXISTS);
        }
        RestaurantCombo newCombo = RecipeConvert.INSTANCE.comboCreateInputConvert(inputVO);
        newCombo = restaurantComboRepository.insert(newCombo);
        return newCombo.id();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean comboUpdate(RecipeComboUpdateInput inputVO) {
        Optional<RestaurantCombo> opDupCombo = restaurantComboRepository.findFirstByComboNameAndIdNot(inputVO.getComboName(), inputVO.getId());
        if(opDupCombo.isPresent()){
            throw exception(COMBO_EXISTS);
        }
        RestaurantCombo updateCombo = RecipeConvert.INSTANCE.comboUpdateInputConvert(inputVO);
        restaurantComboRepository.update(updateCombo);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean comboDeleted(Long id) {
        Optional<RestaurantCombo> opDeleteCombo = restaurantComboRepository.findById(id);
        if(!opDeleteCombo.isPresent()){
            throw exception(COMBO_NOT_EXISTS);
        }
        restaurantComboRepository.deleteById(id);
        return true;
    }

    @Override
    public RecipeComboGetOutput comboGet(Long id) {
        Optional<RestaurantCombo> opDeleteCombo = restaurantComboRepository.findById(id);
        if(!opDeleteCombo.isPresent()){
            throw exception(COMBO_NOT_EXISTS);
        }
        return RecipeConvert.INSTANCE.comboGetOutputConvert(opDeleteCombo.get());
    }

    @Override
    public List<RecipeListQueryComboOutput> listQueryCombo() {
        List<RestaurantCombo> listRestaurantCombo = restaurantComboRepository.listQueryCombo();
        return RecipeConvert.INSTANCE.listQueryComboOutputConvert(listRestaurantCombo);

    }

    @Override
    public PageResult<RecipePageQueryDetailOutput> pageQueryDetail(RecipePageQueryDetailInput inputVO) {
        Page<RestaurantRecipe> pageRestaurantRecipe = restaurantRecipeRepository.pageQueryDetail(inputVO);
        List<RecipePageQueryDetailOutput> listRestaurantRecipe = RecipeConvert.INSTANCE.pageQueryDetailOutputConvert(pageRestaurantRecipe.getRows());
        return new PageResult<>(listRestaurantRecipe, pageRestaurantRecipe.getTotalRowCount());
    }

}
